package tr.edu.metu.is.mega.client.course.instructor.students;

import java.util.ArrayList;
import java.util.List;

import tr.edu.metu.is.mega.client.core.AsyncCallbackAdapter;
import tr.edu.metu.is.mega.client.core.DialogCallback;
import tr.edu.metu.is.mega.client.core.MegaUtil;
import tr.edu.metu.is.mega.client.core.event.SelectionEventBus;
import tr.edu.metu.is.mega.client.course.CourseChangeEvent;
import tr.edu.metu.is.mega.client.resource.MEGAIconBundle;
import tr.edu.metu.is.mega.client.resource.MEGAResourceBundle;
import tr.edu.metu.is.mega.client.resource.MEGAResources;
import tr.edu.metu.is.mega.client.service.GwtCourseService;
import tr.edu.metu.is.mega.client.service.GwtCourseServiceAsync;
import tr.edu.metu.is.mega.client.user.UserSelectDialog;
import tr.edu.metu.is.mega.common.dto.CourseDTO;
import tr.edu.metu.is.mega.common.dto.CourseStudentDTO;
import tr.edu.metu.is.mega.common.dto.UserDTO;
import tr.edu.metu.is.mega.common.dto.UserRole;

import com.extjs.gxt.ui.client.Style.SelectionMode;
import com.extjs.gxt.ui.client.data.BeanModel;
import com.extjs.gxt.ui.client.data.BeanModelFactory;
import com.extjs.gxt.ui.client.data.BeanModelLookup;
import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.Window;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.grid.CheckBoxSelectionModel;
import com.extjs.gxt.ui.client.widget.grid.ColumnConfig;
import com.extjs.gxt.ui.client.widget.grid.ColumnModel;
import com.extjs.gxt.ui.client.widget.grid.EditorGrid;
import com.extjs.gxt.ui.client.widget.grid.Grid;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.toolbar.ToolBar;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.AbstractImagePrototype;

/**
 * Dialog for course student management.
 */
public class CourseStudentsManagementDialog extends Window {

    private MEGAResourceBundle resourceBundle;

    private MEGAIconBundle iconBundle;

    private Grid<BeanModel> grid;

    private BeanModelFactory beanModelFactory;

    private final CourseDTO course;

    private final boolean selectMode;

    private DialogCallback<CourseStudentDTO> callback;

    /**
     * Default constructor.
     * 
     * @param course course to display students
     */
    public CourseStudentsManagementDialog(CourseDTO course) {
        this(course, false);
    }

    /**
     * Default constructor.
     * 
     * @param course course to display students
     * @param selectMode if true, save button selects students.
     */
    public CourseStudentsManagementDialog(CourseDTO course, boolean selectMode) {
        this.course = course;
        this.selectMode = selectMode;
    }

    public void select(DialogCallback<CourseStudentDTO> callback) {
        show();
        this.callback = callback;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void onRender(Element parent, int pos) {
        super.onRender(parent, pos);
        resourceBundle = MEGAResources.RESOURCEBUNDLE;
        iconBundle = MEGAResources.ICONBUNDLE;
        beanModelFactory = BeanModelLookup.get().getFactory(CourseStudentDTO.class);

        setHeading(resourceBundle.courseStudentsManagementHeading());

        setSize(350, 500);
        setLayout(new FitLayout());
        setModal(true);
        ContentPanel panel = new ContentPanel();
        panel.setHeaderVisible(false);
        panel.setLayout(new FitLayout());

        panel.add(getGrid());
        panel.setTopComponent(getToolBar());
        add(panel);

        Button saveButton = new Button(selectMode ? "Save & Select" : "Save");
        saveButton.addSelectionListener(new SelectionListener<ButtonEvent>() {

            @Override
            public void componentSelected(ButtonEvent ce) {
                hide();
                course.setStudents(getStudents());
                getService().updateCourse(course, new AsyncCallbackAdapter<CourseDTO>() {

                    @Override
                    public void onSuccess(CourseDTO result) {
                        SelectionEventBus.getInstance().fireEvent(CourseChangeEvent.UPDATE, result);
                        if (selectMode) {
                            callback.onOk(getSelectedStudents());
                        }
                    }
                });
            }
        });
        panel.addButton(saveButton);

        Button cancelButton = new Button("Cancel");
        cancelButton.addSelectionListener(new SelectionListener<ButtonEvent>() {

            @Override
            public void componentSelected(ButtonEvent ce) {
                hide();
            }
        });
        panel.addButton(cancelButton);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void afterRender() {
        super.afterRender();
        if (course != null) {
            setStudents(course.getStudents());
        }
    }

    /**
     * Initializes and returns toolbar.
     * 
     * @return toolbar
     */
    private ToolBar getToolBar() {
        ToolBar toolBar = new ToolBar();
        toolBar.setMinButtonWidth(70);
        toolBar.setSpacing(5);

        Button addButton = new Button("Register", AbstractImagePrototype.create(iconBundle.add()));
        addButton.addSelectionListener(new SelectionListener<ButtonEvent>() {

            @Override
            public void componentSelected(ButtonEvent ce) {
                UserSelectDialog dialog = new UserSelectDialog(true, false, UserRole.STUDENT);
                dialog.select(new DialogCallback<UserDTO>() {

                    @Override
                    public void onOk(UserDTO param) {
                        for (CourseStudentDTO studentDTO : course.getStudents()) {
                            if (studentDTO.getUser().getPkid() == param.getPkid()) {
                                return;
                            }
                        }
                        CourseStudentDTO dto = new CourseStudentDTO();
                        dto.setCourse(course);
                        dto.setUser(param);

                        BeanModel model = beanModelFactory.createModel(dto);
                        if (!grid.getStore().contains(model)) {
                            grid.getStore().add(model);
                        }
                    }

                    @Override
                    public void onOk(List<UserDTO> params) {
                        List<UserDTO> removeList = new ArrayList<UserDTO>(params.size());
                        for (UserDTO param : params) {
                            for (CourseStudentDTO studentDTO : course.getStudents()) {
                                if (studentDTO.getUser().getPkid() == param.getPkid()) {
                                    removeList.add(param);
                                }
                            }
                        }
                        params.removeAll(removeList);
                        for (UserDTO userDTO : params) {
                            CourseStudentDTO dto = new CourseStudentDTO();
                            dto.setCourse(course);
                            dto.setUser(userDTO);
                            BeanModel model = beanModelFactory.createModel(dto);
                            if (!grid.getStore().contains(model)) {
                                grid.getStore().add(model);
                            }
                        }
                    }

                    @Override
                    public void onCancel() {
                    }
                });

            }
        });

        Button deleteButton = new Button("Unregister", AbstractImagePrototype.create(iconBundle.delete()));
        deleteButton.addSelectionListener(new SelectionListener<ButtonEvent>() {

            @Override
            public void componentSelected(ButtonEvent ce) {
                if (grid.getSelectionModel().getSelectedItem() != null) {
                    grid.getStore().remove(grid.getSelectionModel().getSelectedItem());
                }
            }
        });

        Button pullFromMetuOnline = new Button(resourceBundle.pullFromMetuOnline(), AbstractImagePrototype.create(iconBundle.importInto()));
        pullFromMetuOnline.addSelectionListener(new SelectionListener<ButtonEvent>() {

            @Override
            public void componentSelected(ButtonEvent ce) {
                getService().pullStudentsFromMETUOnline(course, new AsyncCallbackAdapter<List<CourseStudentDTO>>() {

                    @Override
                    public void onSuccess(List<CourseStudentDTO> result) {
                        for (CourseStudentDTO userDTO : result) {
                            BeanModel model = beanModelFactory.createModel(userDTO);
                            if (!grid.getStore().contains(model)) {
                                grid.getStore().add(model);
                            }
                        }
                    }
                });
            }
        });

        toolBar.add(addButton);
        toolBar.add(deleteButton);
        toolBar.add(pullFromMetuOnline);

        return toolBar;
    }

    /**
     * Returns activity grid.
     * 
     * @return grid
     */
    private Grid<BeanModel> getGrid() {
        if (grid == null) {
            ListStore<BeanModel> store = new ListStore<BeanModel>();
            List<ColumnConfig> columns = new ArrayList<ColumnConfig>();
            CheckBoxSelectionModel<BeanModel> cbsm = null;
            if (selectMode) {
                cbsm = new CheckBoxSelectionModel<BeanModel>();
                cbsm.setSelectionMode(SelectionMode.MULTI);
                columns.add(cbsm.getColumn());
            }

            columns.add(new ColumnConfig(CourseStudentDTO.FIELD_STUDENT_NO, resourceBundle.courseStudentsManagementStudentNo(), 150));
            columns.add(new ColumnConfig(CourseStudentDTO.FIELD_STUDENT_NAME, resourceBundle.courseStudentsManagementStudentName(), 150));

            ColumnModel cm = new ColumnModel(columns);

            grid = new EditorGrid<BeanModel>(store, cm);
            if (selectMode) {
                grid.setSelectionModel(cbsm);
                grid.addPlugin(cbsm);
            }

            MegaUtil.decoradeGridViewWithAutoHeight(grid, true);

        }
        return grid;
    }

    /**
     * Adds students to grid
     * 
     * @param studentList
     */
    public void setStudents(List<CourseStudentDTO> studentList) {
        grid.getStore().removeAll();
        for (CourseStudentDTO activity : studentList) {
            grid.getStore().add(beanModelFactory.createModel(activity));
        }
    }

    /**
     * Gets students from grid.
     * 
     * @return list of students
     */
    public List<CourseStudentDTO> getStudents() {
        List<CourseStudentDTO> students = new ArrayList<CourseStudentDTO>(grid.getStore().getModels().size());
        for (BeanModel model : grid.getStore().getModels()) {
            CourseStudentDTO student = (CourseStudentDTO) model.getBean();
            students.add(student);
        }
        return students;
    }

    /**
     * Gets selected students from grid.
     * 
     * @return list of students
     */
    public List<CourseStudentDTO> getSelectedStudents() {
        List<CourseStudentDTO> students = new ArrayList<CourseStudentDTO>(grid.getSelectionModel().getSelectedItems().size());
        for (BeanModel model : grid.getSelectionModel().getSelectedItems()) {
            CourseStudentDTO student = (CourseStudentDTO) model.getBean();
            students.add(student);
        }
        return students;
    }

    /**
     * Returns GWT course service instance.
     * 
     * @return service
     */
    public static GwtCourseServiceAsync getService() {
        return GwtCourseService.Util.getInstance();
    }

}
